/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.games.epkb.controller;

import it.polimi.games.epkb.controller.exceptions.IllegalOrphanException;
import it.polimi.games.epkb.controller.exceptions.NonexistentEntityException;
import it.polimi.games.epkb.controller.exceptions.PreexistingEntityException;
import it.polimi.games.epkb.entityClasses.AssociationRule;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import it.polimi.games.epkb.entityClasses.Consequent;
import java.util.ArrayList;
import java.util.Collection;
import it.polimi.games.epkb.entityClasses.Antecedent;
import javax.transaction.UserTransaction;

/**
 *
 * @author plebani
 */
public class AssociationRuleJpaController implements Serializable {

    public AssociationRuleJpaController(EntityManagerFactory emf) {
        this.utx = null;
        this.emf = emf;
    }

    public AssociationRuleJpaController(UserTransaction utx, EntityManagerFactory emf) {
        this.utx = utx;
        this.emf = emf;
    }
    private UserTransaction utx = null;
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(AssociationRule associationRule) throws PreexistingEntityException, Exception {
        if (associationRule.getConsequentCollection() == null) {
            associationRule.setConsequentCollection(new ArrayList<Consequent>());
        }
        if (associationRule.getAntecedentCollection() == null) {
            associationRule.setAntecedentCollection(new ArrayList<Antecedent>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Collection<Consequent> attachedConsequentCollection = new ArrayList<Consequent>();
            for (Consequent consequentCollectionConsequentToAttach : associationRule.getConsequentCollection()) {
                consequentCollectionConsequentToAttach = em.getReference(consequentCollectionConsequentToAttach.getClass(), consequentCollectionConsequentToAttach.getConsequentPK());
                attachedConsequentCollection.add(consequentCollectionConsequentToAttach);
            }
            associationRule.setConsequentCollection(attachedConsequentCollection);
            Collection<Antecedent> attachedAntecedentCollection = new ArrayList<Antecedent>();
            for (Antecedent antecedentCollectionAntecedentToAttach : associationRule.getAntecedentCollection()) {
                antecedentCollectionAntecedentToAttach = em.getReference(antecedentCollectionAntecedentToAttach.getClass(), antecedentCollectionAntecedentToAttach.getAntecedentPK());
                attachedAntecedentCollection.add(antecedentCollectionAntecedentToAttach);
            }
            associationRule.setAntecedentCollection(attachedAntecedentCollection);
            em.persist(associationRule);
            for (Consequent consequentCollectionConsequent : associationRule.getConsequentCollection()) {
                AssociationRule oldAssociationRuleOfConsequentCollectionConsequent = consequentCollectionConsequent.getAssociationRule();
                consequentCollectionConsequent.setAssociationRule(associationRule);
                consequentCollectionConsequent = em.merge(consequentCollectionConsequent);
                if (oldAssociationRuleOfConsequentCollectionConsequent != null) {
                    oldAssociationRuleOfConsequentCollectionConsequent.getConsequentCollection().remove(consequentCollectionConsequent);
                    oldAssociationRuleOfConsequentCollectionConsequent = em.merge(oldAssociationRuleOfConsequentCollectionConsequent);
                }
            }
            for (Antecedent antecedentCollectionAntecedent : associationRule.getAntecedentCollection()) {
                AssociationRule oldAssociationRuleOfAntecedentCollectionAntecedent = antecedentCollectionAntecedent.getAssociationRule();
                antecedentCollectionAntecedent.setAssociationRule(associationRule);
                antecedentCollectionAntecedent = em.merge(antecedentCollectionAntecedent);
                if (oldAssociationRuleOfAntecedentCollectionAntecedent != null) {
                    oldAssociationRuleOfAntecedentCollectionAntecedent.getAntecedentCollection().remove(antecedentCollectionAntecedent);
                    oldAssociationRuleOfAntecedentCollectionAntecedent = em.merge(oldAssociationRuleOfAntecedentCollectionAntecedent);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findAssociationRule(associationRule.getId()) != null) {
                throw new PreexistingEntityException("AssociationRule " + associationRule + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(AssociationRule associationRule) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            AssociationRule persistentAssociationRule = em.find(AssociationRule.class, associationRule.getId());
            Collection<Consequent> consequentCollectionOld = persistentAssociationRule.getConsequentCollection();
            Collection<Consequent> consequentCollectionNew = associationRule.getConsequentCollection();
            Collection<Antecedent> antecedentCollectionOld = persistentAssociationRule.getAntecedentCollection();
            Collection<Antecedent> antecedentCollectionNew = associationRule.getAntecedentCollection();
            List<String> illegalOrphanMessages = null;
            for (Consequent consequentCollectionOldConsequent : consequentCollectionOld) {
                if (!consequentCollectionNew.contains(consequentCollectionOldConsequent)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain Consequent " + consequentCollectionOldConsequent + " since its associationRule field is not nullable.");
                }
            }
            for (Antecedent antecedentCollectionOldAntecedent : antecedentCollectionOld) {
                if (!antecedentCollectionNew.contains(antecedentCollectionOldAntecedent)) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain Antecedent " + antecedentCollectionOldAntecedent + " since its associationRule field is not nullable.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Collection<Consequent> attachedConsequentCollectionNew = new ArrayList<Consequent>();
            for (Consequent consequentCollectionNewConsequentToAttach : consequentCollectionNew) {
                consequentCollectionNewConsequentToAttach = em.getReference(consequentCollectionNewConsequentToAttach.getClass(), consequentCollectionNewConsequentToAttach.getConsequentPK());
                attachedConsequentCollectionNew.add(consequentCollectionNewConsequentToAttach);
            }
            consequentCollectionNew = attachedConsequentCollectionNew;
            associationRule.setConsequentCollection(consequentCollectionNew);
            Collection<Antecedent> attachedAntecedentCollectionNew = new ArrayList<Antecedent>();
            for (Antecedent antecedentCollectionNewAntecedentToAttach : antecedentCollectionNew) {
                antecedentCollectionNewAntecedentToAttach = em.getReference(antecedentCollectionNewAntecedentToAttach.getClass(), antecedentCollectionNewAntecedentToAttach.getAntecedentPK());
                attachedAntecedentCollectionNew.add(antecedentCollectionNewAntecedentToAttach);
            }
            antecedentCollectionNew = attachedAntecedentCollectionNew;
            associationRule.setAntecedentCollection(antecedentCollectionNew);
            associationRule = em.merge(associationRule);
            for (Consequent consequentCollectionNewConsequent : consequentCollectionNew) {
                if (!consequentCollectionOld.contains(consequentCollectionNewConsequent)) {
                    AssociationRule oldAssociationRuleOfConsequentCollectionNewConsequent = consequentCollectionNewConsequent.getAssociationRule();
                    consequentCollectionNewConsequent.setAssociationRule(associationRule);
                    consequentCollectionNewConsequent = em.merge(consequentCollectionNewConsequent);
                    if (oldAssociationRuleOfConsequentCollectionNewConsequent != null && !oldAssociationRuleOfConsequentCollectionNewConsequent.equals(associationRule)) {
                        oldAssociationRuleOfConsequentCollectionNewConsequent.getConsequentCollection().remove(consequentCollectionNewConsequent);
                        oldAssociationRuleOfConsequentCollectionNewConsequent = em.merge(oldAssociationRuleOfConsequentCollectionNewConsequent);
                    }
                }
            }
            for (Antecedent antecedentCollectionNewAntecedent : antecedentCollectionNew) {
                if (!antecedentCollectionOld.contains(antecedentCollectionNewAntecedent)) {
                    AssociationRule oldAssociationRuleOfAntecedentCollectionNewAntecedent = antecedentCollectionNewAntecedent.getAssociationRule();
                    antecedentCollectionNewAntecedent.setAssociationRule(associationRule);
                    antecedentCollectionNewAntecedent = em.merge(antecedentCollectionNewAntecedent);
                    if (oldAssociationRuleOfAntecedentCollectionNewAntecedent != null && !oldAssociationRuleOfAntecedentCollectionNewAntecedent.equals(associationRule)) {
                        oldAssociationRuleOfAntecedentCollectionNewAntecedent.getAntecedentCollection().remove(antecedentCollectionNewAntecedent);
                        oldAssociationRuleOfAntecedentCollectionNewAntecedent = em.merge(oldAssociationRuleOfAntecedentCollectionNewAntecedent);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                String id = associationRule.getId();
                if (findAssociationRule(id) == null) {
                    throw new NonexistentEntityException("The associationRule with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(String id) throws IllegalOrphanException, NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            AssociationRule associationRule;
            try {
                associationRule = em.getReference(AssociationRule.class, id);
                associationRule.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The associationRule with id " + id + " no longer exists.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            Collection<Consequent> consequentCollectionOrphanCheck = associationRule.getConsequentCollection();
            for (Consequent consequentCollectionOrphanCheckConsequent : consequentCollectionOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This AssociationRule (" + associationRule + ") cannot be destroyed since the Consequent " + consequentCollectionOrphanCheckConsequent + " in its consequentCollection field has a non-nullable associationRule field.");
            }
            Collection<Antecedent> antecedentCollectionOrphanCheck = associationRule.getAntecedentCollection();
            for (Antecedent antecedentCollectionOrphanCheckAntecedent : antecedentCollectionOrphanCheck) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This AssociationRule (" + associationRule + ") cannot be destroyed since the Antecedent " + antecedentCollectionOrphanCheckAntecedent + " in its antecedentCollection field has a non-nullable associationRule field.");
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            em.remove(associationRule);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<AssociationRule> findAssociationRuleEntities() {
        return findAssociationRuleEntities(true, -1, -1);
    }

    public List<AssociationRule> findAssociationRuleEntities(int maxResults, int firstResult) {
        return findAssociationRuleEntities(false, maxResults, firstResult);
    }

    private List<AssociationRule> findAssociationRuleEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(AssociationRule.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public AssociationRule findAssociationRule(String id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(AssociationRule.class, id);
        } finally {
            em.close();
        }
    }

    public int getAssociationRuleCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<AssociationRule> rt = cq.from(AssociationRule.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
    
}
